﻿// ***********************************************************************
// Assembly         : GooglePredict
// Author           : aj
// Created          : 10-08-2010
//
// Last Modified By : aj
// Last Modified On : 10-11-2010
// Description      : 
//
//
// ***********************************************************************
namespace Google.API.Predict.Auth
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Responses;

    /// <summary>
    /// Parses ClientLogin Responses
    /// </summary>
    public class ClientLoginResponse : BaseResponse
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ClientLoginResponse"/> class using the raw text response
        /// <param name="response">Raw Response from ClientLogin</param>
        /// </summary>
        internal ClientLoginResponse(string response)
        {
            var fields = ResponseToDictionary(response);

            if (fields.Count > 0)
            {
                ErrorCode = ClientLoginErrorCode.None;

                // 200 OK PARSING
                if (fields.ContainsKey("SID"))
                {
                    SID = fields["SID"];
                }

                if (fields.ContainsKey("LSID"))
                {
                    LSID = fields["LSID"];
                }

                if (fields.ContainsKey("Auth"))
                {
                    Auth = fields["Auth"];
                    AuthSource = AuthSourceType.Google;
                }
                else
                {
                    ErrorCode = ClientLoginErrorCode.NoAuth;
                    AuthSource = AuthSourceType.None;
                }

                // 403 ERROR CODE PARSING
                if (fields.ContainsKey("Error"))
                {
                    ErrorCode = ClientLoginErrors.ResolveErrorCode(fields["Error"]);
                }

                // 403 CAPTCHA PARSING
                if (fields.ContainsKey("Url"))
                {
                    try
                    {
                        Uri = new Uri(fields["Url"]);
                    }
                    catch
                    {
                        Uri = new Uri("http://www.google.com");
                    }
                }

                if (fields.ContainsKey("CaptchaToken"))
                {
                    CaptchaToken = fields["CaptchaToken"];
                }

                if (fields.ContainsKey("CaptchaUrl"))
                {
                    CaptchaUri = new Uri("http://www.google.com/accounts/Captcha?ctoken=" + fields["CaptchaToken"]);
                }
            }
            else
            {
                ErrorCode = ClientLoginErrorCode.NoData;
            }

            ErrorCodeDescription = ClientLoginErrors.ResolveErrorMessage(ErrorCode);
        }

        /// <summary>
        /// Specifies where the Auth key came from
        /// </summary>
        public enum AuthSourceType
        {
            /// <summary>
            /// No Auth key has been defined
            /// </summary>
            None,

            /// <summary>
            /// Auth key was obtained from response
            /// </summary>
            Google,

            /// <summary>
            /// Auth key was passed via constructor
            /// </summary>
            UserDefined
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ClientLoginResponse"/> class. Used by only private static creation.
        /// </summary>
        private ClientLoginResponse()
        {
        }

        /// <summary>
        /// Gets SID that was parsed from raw Client Login string
        /// </summary>
        /// <value>The SID.</value>
        public string SID
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets LSID that was parsed from raw Client Login string
        /// </summary>
        /// <value>The LSID.</value>
        public string LSID
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets Authentication token used to access api.
        /// </summary>
        /// <value>The auth.</value>
        public string Auth
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the auth source.
        /// </summary>
        /// <value>The source from which the Auth key originated</value>
        public AuthSourceType AuthSource
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets Uri to the CAPTCHA image if required.
        /// </summary>
        /// <value>The URI.</value>
        public Uri Uri
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets Error code parsed from response
        /// </summary>
        /// <value>The error code.</value>
        public ClientLoginErrorCode ErrorCode
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the error code description.
        /// </summary>
        /// <value>The error code description</value>
        public string ErrorCodeDescription
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets Captcha Token (null if not required)
        /// </summary>
        /// <value>The captcha token.</value>
        public string CaptchaToken
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets Captcha Uri (null if not required)
        /// </summary>
        /// <value>The captcha URI.</value>
        public Uri CaptchaUri
        {
            get;
            private set;
        }

        /// <summary>
        /// Initializes a new instance of the ClientLoginResponse class.
        /// </summary>
        /// <param name="auth">VAuth key to initialize the response with</param>
        /// <returns>
        /// Client Login Response with auth key and error code set to None, authsource set to UserDefined - no other fields are initialized!
        /// </returns>
        public static ClientLoginResponse CreateFromAuth(string auth)
        {
            return new ClientLoginResponse
            {
                Auth = auth,
                AuthSource = AuthSourceType.UserDefined,
                ErrorCode = ClientLoginErrorCode.None
            };
        }

        /// <summary>
        /// Parses a raw Client Login response into a Dictionary
        /// </summary>
        /// <param name="response">raw response from Client Login</param>
        /// <returns>
        /// Dictionary containing fields and values parsed from raw Client Login response
        /// </returns>
        private static Dictionary<string, string> ResponseToDictionary(string response)
        {
            Dictionary<string, string> responseDictionary;
            if (!string.IsNullOrEmpty(response))
            {
                try
                {
                    // Sample Responses from - http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html
                    // Parses the response according to Google's Documentation
                    // HTTP/1.0 200 OK
                    // Server: GFE/1.3
                    // Content-Type: text/plain 

                    // SID=DQAAAGgA...7Zg8CTN
                    // LSID=DQAAAGsA...lk8BBbG
                    // Auth=DQAAAGgA...dk3fA5N
                    //
                    // HTTP/1.0 403 Access Forbidden
                    // Server: GFE/1.3
                    // Content-Type: text/plain
                    //
                    // Url=http://www.google.com/login/captcha
                    // Error=CaptchaRequired
                    // CaptchaToken=DQAAAGgA...dkI1LK9
                    // CaptchaUrl=Captcha?ctoken=HiteT4b0Bk5Xg18_AcVoP6-yFkHPibe7O9EqxeiI7lUSN
                    var responseValues = response.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
                    responseDictionary = responseValues.Where(r => r.Contains('=') && r.Split('=').Length >= 2).ToDictionary(k => k.Split('=')[0], e => new string(e.Split('=').Skip(1).SelectMany(s => s).ToArray()));
                }
                catch
                {
                    responseDictionary = new Dictionary<string, string>();
                }
            }
            else
            {
                responseDictionary = new Dictionary<string, string>();
            }

            return responseDictionary;
        }
    }
}
